// if ('serviceWorker' in navigator) {
//   navigator.serviceWorker.register('service-worker.js', {
//     scope: './'
//   }).then(function (registration) {
//     var serviceWorker;
//     if (registration.installing) {
//       serviceWorker = registration.installing;
//       document.querySelector('#kind').textContent = 'installing';
//     } else if (registration.waiting) {
//       serviceWorker = registration.waiting;
//       document.querySelector('#kind').textContent = 'waiting';
//     } else if (registration.active) {
//       serviceWorker = registration.active;
//       document.querySelector('#kind').textContent = 'active';
//     }
//     if (serviceWorker) {
//       // logState(serviceWorker.state);
//       serviceWorker.addEventListener('statechange', function (e) {
//         // logState(e.target.state);
//       });
//     }
//   }).catch(function (error) {
//     // Something went wrong during registration. The service-worker.js file
//     // might be unavailable or contain a syntax error.
//   });
// } else {
//   // The current browser doesn't support service workers.
// }






// 注册你的 worker
// if ('serviceWorker' in navigator) {
//   // 注意，这个文件的 url 是相对于 origin，而不是相对于引用它的那个 JS 文件
//   // scope 参数是选填的，可以被用来指定你想让 service worker 控制的内容的子目录
//   navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/sw-test/' }).then(function (reg) {
//     // registration worked
//     console.log('Registration succeeded. Scope is ' + reg.scope);
//   }).catch(function (error) {
//     // registration failed
//     console.log('Registration failed with ' + error);
//   });
// }

// 填充你的缓存
// this.addEventListener('install', function (event) {
//   event.waitUntil(
//     caches.open('v1').then(function (cache) {
//       return cache.addAll([
//         '/sw-test/',
//         '/sw-test/index.html',
//         '/sw-test/style.css',
//         '/sw-test/app.js',
//         '/sw-test/image-list.js',
//         '/sw-test/star-wars-logo.jpg',
//         '/sw-test/gallery/',
//         '/sw-test/gallery/bountyHunters.jpg',
//         '/sw-test/gallery/myLittleVader.jpg',
//         '/sw-test/gallery/snowTroopers.jpg'
//       ]);
//     })
//   );
// });



// this.addEventListener('fetch', function (event) {
//   event.respondWith(
//     caches.match(event.request).then(function () {
//       return fetch(event.request).then(function (response) {
//         return caches.open('v1').then(function (cache) {
//           cache.put(event.request, response.clone());
//           return response;
//         });
//       });
//     }).catch(function () {
//       return caches.match('/sw-test/gallery/myLittleVader.jpg');
//     })
//   );
// });



// 更新并删除旧版本

// self.addEventListener('install', function (event) {
//   event.waitUntil(
//     caches.open('v2').then(function (cache) {
//       return cache.addAll([
//         '/sw-test/',
//         '/sw-test/index.html',
//         '/sw-test/style.css',
//         '/sw-test/app.js',
//         '/sw-test/image-list.js',

//         // …

//         // include other new resources for the new version...
//       ]);
//     })
//   );
// });


// self.addEventListener('activate', function (event) {
//   var cacheWhitelist = ['v2'];

//   event.waitUntil(
//     caches.keys().then(function (keyList) {
//       return Promise.all(keyList.map(function (key) {
//         if (cacheWhitelist.indexOf(key) === -1) {
//           return caches.delete(key);
//         }
//       }));
//     })
//   );
// });

// service worker 函数像一个代理服务器一样，允许你修改请求和响应，用他们的缓存替代它们等等。


// 在 HTTPS 下运行你的程序
// 文件的地址没有写对— 需要相对于 origin , 而不是 app 的根目录
// service worker 在不同的 origin 而不是你的 app 的



// service worker 只能抓取在 service worker scope 里从客户端发出的请求。
// 最大的 scope 是 service worker 所在的地址
// 如果你的 service worker 被激活在一个有 Service-Worker-Allowed header 的客户端，你可以为 service worker 指定一个最大的 scope 的列表

// 我们使用了 Service Worker 的新的标志性的存储 API — cache — 一个 service worker 上的全局对象，它使我们可以存储网络响应发来的资源，并且根据它们的请求来生成 key。这个 API 和浏览器的标准的缓存工作原理很相似，但是是特定你的域的。它会一直持久存在，直到你告诉它不再存储，你拥有全部的控制权。

var squareRotation = 0.0;
var cubeTexture
function main() {
  const canvas = document.querySelector("#glcanvas");
  const gl = canvas.getContext("webgl"); // 初始化 WebGL 上下文
  if (gl === null) { alert("Unable to initialize WebGL. Your browser or machine may not support it."); return; }
  gl.clearColor(0, 0, 0, 1.0); // 指定擦除颜色
  gl.clear(gl.COLOR_BUFFER_BIT);// 清除缓冲区
  // 顶点着色器源代码
  const vsSource =
    // 获取顶点颜色数据
    // `
    //   attribute vec3 aVertexPosition;
    //   attribute vec4 aVertexColor;
    //   uniform mat4 uModelViewMatrix;
    //   uniform mat4 uProjectionMatrix;
    //   varying lowp vec4 vColor;
    //   void main() {
    //     gl_Position = uProjectionMatrix* uModelViewMatrix * vec4(aVertexPosition, 1.0);
    //     vColor = aVertexColor;
    //   }
    // `;
    // 获取纹理坐标数据
    `
    attribute vec3 aVertexPosition;
    attribute vec2 aTextureCoord;

    uniform mat4 uMVMatrix;
    uniform mat4 uPMatrix;

    varying highp vec2 vTextureCoord;

    void main(void) {
      gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
      vTextureCoord = aTextureCoord;
    }
  `
  // 片段着色器源代码
  const fsSource =
    // `
    //   varying lowp vec4 vColor;
    //   void main() {
    //     gl_FragColor = vColor;
    //   }
    // `;
    `
  varying highp vec2 vTextureCoord;
  uniform sampler2D uSampler;
  void main(void) {
    gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
  }
  `

  const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
  const programInfo = {// 组装传递数据
    program: shaderProgram,
    attribLocations: {
      vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
      vertexColorAttribute: gl.getAttribLocation(shaderProgram, "aVertexColor"),
      textureCoordAttribute: gl.getAttribLocation(shaderProgram, "aTextureCoord")
    },
    uniformLocations: {
      projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
      modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
    },
  };
  const buffers = initBuffers(gl);
  initTextures(gl)
  // drawScene(gl, programInfo, buffers);
  var then = 0;
  // 重复渲染
  function render(now) {
    now *= 0.001;  // 转换成秒
    const deltaTime = now - then;
    then = now;
    drawScene(gl, programInfo, buffers, deltaTime);
    squareRotation += deltaTime;
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}

//  初始化着色器程序，让 WebGL 知道如何绘制我们的数据
function initShaderProgram(gl, vsSource, fsSource) {
  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);// 创建着色器
  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
  const shaderProgram = gl.createProgram();// 创建着色器程序
  gl.attachShader(shaderProgram, vertexShader);// 程序附加着色器
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);// 连接程序与着色器
  // 创建失败，alert
  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`); return null; }
  return shaderProgram;
}

// 创建指定类型的着色器，上传源码并编译.返回编译的着色器
function loadShader(gl, type, source) {
  const shader = gl.createShader(type);// 创建着色器
  gl.shaderSource(shader, source);// 将源代码发送到着色器
  gl.compileShader(shader);// 编译
  // 检查编译结果
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert(`An error occurred compiling the shaders: ${gl.getShaderInfoLog(shader)}`); gl.deleteShader(shader); return null; }
  return shader;
}
// 创建一个缓冲器来存储它的顶点
function initBuffers(gl) {
  return initPositionBuffer(gl);
}
function initPositionBuffer(gl) {
  const positionBuffer = gl.createBuffer();// 创建缓冲对象
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);// 绑定上下文
  const positions = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0];// 正方形顶点位置
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); // 建立顶点对象
  const colorBuffer = gl.createBuffer(); // 颜色缓冲
  const colors = [
    1.0, 1.0, 1.0, 1.0,    // 白
    1.0, 0.0, 0.0, 1.0,    // 红
    0.0, 1.0, 0.0, 1.0,    // 绿
    0.0, 0.0, 1.0, 1.0,    // 蓝
  ];
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
  // 映射纹理到面
  cubeVerticesTextureCoordBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
  var textureCoordinates = [
    // Front
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,
    0.0, 1.0,
    // Back
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,
    0.0, 1.0,
    // Top
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,
    0.0, 1.0,
    // Bottom
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,
    0.0, 1.0,
    // Right
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,
    0.0, 1.0,
    // Left
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,
    0.0, 1.0
  ];

  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gl.STATIC_DRAW);
  return { position: positionBuffer, color: colorBuffer, textureCoordinates };
}
// 绘制场景
function drawScene(gl, programInfo, buffers) {
  gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
  gl.clearDepth(1.0); // Clear everything
  gl.enable(gl.DEPTH_TEST); // Enable depth testing
  gl.depthFunc(gl.LEQUAL); // Near things obscure far things
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);// 擦除画布
  // 建立摄像机透视矩阵。设置 45 度的视图角度，并且设置一个适合实际图像的宽高比。指定在摄像机距离 0.1 到 100 单位长度的范围内的物体可见
  const fieldOfView = (45 * Math.PI) / 180;    // 45 度的视图角度
  const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;// 图像的宽高比
  const zNear = 0.1;
  const zFar = 100.0;
  const projectionMatrix = mat4.create();
  mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);// 建立摄像机透视矩阵
  const modelViewMatrix = mat4.create();
  // 移动摄像机 目的矩阵 起始矩阵 移动量
  mat4.translate(modelViewMatrix, modelViewMatrix, [-0.0, 0.0, -6.0]); // 旋转
  mat4.rotate(modelViewMatrix, modelViewMatrix, squareRotation, [0, 0, 1]);
  setPositionAttribute(gl, buffers, programInfo);
  // 使用哪个程序
  gl.useProgram(programInfo.program);
  // 设置着色器uniform
  gl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix, false, projectionMatrix);
  gl.uniformMatrix4fv(programInfo.uniformLocations.modelViewMatrix, false, modelViewMatrix);
  {
    const offset = 0;
    const vertexCount = 4;
    gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
  }
}

function setPositionAttribute(gl, buffers, programInfo) {
  const numComponents = 2; // pull out 2 values per iteration
  const type = gl.FLOAT; // the data in the buffer is 32bit floats
  const normalize = false; // don't normalize
  const stride = 0; // how many bytes to get from one set of values to the next
  const offset = 0; // how many bytes inside the buffer to start from
  gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
  gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition, numComponents, type, normalize, stride, offset);
  gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
  gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
  gl.vertexAttribPointer(programInfo.attribLocations.vertexColorAttribute, 4, type, normalize, stride, offset);
  gl.enableVertexAttribArray(programInfo.attribLocations.vertexColorAttribute);
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
  gl.uniform1i(gl.getUniformLocation(programInfo.program, "uSampler"), 0);

  gl.enableVertexAttribArray(programInfo.attribLocations.textureCoordAttribute);
  gl.vertexAttribPointer(programInfo.attribLocations.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);

}
// 加载纹理,使用图片
function initTextures(gl) {
  cubeTexture = gl.createTexture(); // 创建一个 GL 纹理对象 
  cubeImage = new Image();
  cubeImage.onload = function () { handleTextureLoaded(cubeImage, cubeTexture, gl); }
  cubeImage.src = "test.jpg";
}

function handleTextureLoaded(image, texture, gl) {
  gl.bindTexture(gl.TEXTURE_2D, texture); // 绑定
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); // 图片写到纹理
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
  // 支持非2幂的图片纹理
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.generateMipmap(gl.TEXTURE_2D);
  gl.bindTexture(gl.TEXTURE_2D, null);
}